package com.junt.library.widgets;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CompoundButton;

import com.junt.library.R;
import com.junt.library.utils.Utils;

import androidx.annotation.Nullable;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;

/**
 * custom checkbox
 */
public class CheckView extends View {

    private static final String TAG = "CheckView";
    private OnCheckedChangeListener onCheckedChangeListener;
    /**
     * 是否选中
     */
    private boolean mChecked = false;
    protected GestureDetector gestureDetector;
    private TextPaint paint;
    private int strokeWidth;
    private int strokeColor;
    private int fillColor;
    private String numberText;
    private int textColor;
    private int textSize;

    private int cx, cy;
    /**
     * 选中后的填充色半径相对于宽度的百分比
     */
    private float fillColorRadiusBasis;
    /**
     * 文本高度的一半
     */
    private float textDis;
    private int checkEdge;
    private int radius;

    public CheckView(Context context) {
        this(context, null);
    }

    public CheckView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CheckView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                return true;
            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                Log.i(TAG, "onSingleTapUp: ");
                mChecked = !mChecked;
                onStateChanged();
                return true;
            }
        });
        paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CheckView);
        mChecked = typedArray.getBoolean(R.styleable.CheckView_check_checked, false);
        strokeWidth = typedArray.getDimensionPixelSize(R.styleable.CheckView_check_stroke_width, (int) Utils.dp2px(context, 1));
        strokeColor = typedArray.getColor(R.styleable.CheckView_check_stroke_color, Color.LTGRAY);
        fillColor = typedArray.getColor(R.styleable.CheckView_check_fill_color, Color.GREEN);
        numberText = String.valueOf(typedArray.getInt(R.styleable.CheckView_check_number, 1));
        textColor = typedArray.getColor(R.styleable.CheckView_check_text_color, Color.WHITE);
        textSize = typedArray.getDimensionPixelSize(R.styleable.CheckView_check_text_size, (int) Utils.dp2px(context, 14));
        paint.setTextSize(textSize);
        checkEdge = typedArray.getDimensionPixelSize(R.styleable.CheckView_check_edge, (int) Utils.dp2px(context, 6));
        typedArray.recycle();
    }

    private void onStateChanged() {
        if (mChecked) {
            startCheckAnim();
        } else {
            invalidate();
            if (onCheckedChangeListener != null) {
                onCheckedChangeListener.onCheckedChanged(CheckView.this, mChecked);
            }
        }
    }

    public void setNumberText(String numberText) {
        this.numberText = numberText;
    }

    public void setChecked(boolean mChecked) {
        this.mChecked = mChecked;
        onStateChanged();
    }

    public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
        this.onCheckedChangeListener = onCheckedChangeListener;
    }

    private void startCheckAnim() {
        ValueAnimator checkAnimator = ValueAnimator.ofFloat(0f, 1).setDuration(250);
        checkAnimator.setInterpolator(new FastOutSlowInInterpolator());
        checkAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                fillColorRadiusBasis = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        checkAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                if (onCheckedChangeListener != null) {
                    onCheckedChangeListener.onCheckedChanged(CheckView.this, mChecked);
                }
            }
        });
        checkAnimator.start();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        cx = w / 2;
        cy = h / 2;
        radius = Math.min(cx, cy) - checkEdge;
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        textDis = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (!mChecked) {
            paint.setStrokeWidth(strokeWidth);
            paint.setColor(strokeColor);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawCircle(cx, cy, radius - strokeWidth, paint);
        } else {
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(fillColor);
            canvas.drawCircle(cx, cy, fillColorRadiusBasis * radius, paint);

            paint.setStyle(Paint.Style.FILL);
            paint.setColor(textColor);
            float textWidth = paint.measureText(numberText);
            canvas.drawText(numberText, cx - textWidth / 2, cy + textDis, paint);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = getMeasureSize(widthMeasureSpec);
        int height = getMeasureSize(heightMeasureSpec);
        setMeasuredDimension(
                Math.min(width, height) + checkEdge,
                Math.min(width, height) + checkEdge);
    }

    private int getMeasureSize(int measureSpec) {
        if (MeasureSpec.getMode(measureSpec) == MeasureSpec.UNSPECIFIED) {
            return (int) Utils.dp2px(getContext(), 25);
        }
        return MeasureSpec.getSize(measureSpec);
    }

    /**
     * Interface definition for a callback to be invoked when the checked state
     * of a compound button changed.
     */
    public static interface OnCheckedChangeListener {
        /**
         * Called when the checked state of a compound button has changed.
         *
         * @param checkView The check view whose state has changed.
         * @param isChecked The new checked state of buttonView.
         */
        void onCheckedChanged(CheckView checkView, boolean isChecked);
    }
}
